//@version=6
indicator("Williams-Alligator Spread Oscillator (WASO)", "WASO", overlay=false)

// =====================================================
// Inputs
// =====================================================
// — Alligator (calculation for WASO)
srcOpt   = input.source(hl2, "Source", group="Alligator")
jawLen   = input.int(8,  "Jaw Length",   group="Alligator", minval=1)
teethLen = input.int(6,  "Teeth Length", group="Alligator", minval=1)
lipsLen  = input.int(2,  "Lips Length",  group="Alligator", minval=1)

// Toggle: Use classic SMMA formulation for Alligator calc (no forward plotting shift in WASO pane)
useClassicAlligator = input.bool(true, "Use classic SMMA Alligator for calc", group="Alligator",
     tooltip="Calculates Jaw/Teeth/Lips with SMMA (aka RMA). Offsets used in the classic price overlay are NOT applied here to avoid lookahead. For visual price overlay, use a separate Alligator overlay script.")

smoothType = input.string("SMMA (RMA)", "Smoothing Type", options=["SMMA (RMA)", "EMA"], group="Alligator")

// — Volatility / Normalization
atrLen   = input.int(12, "ATR Length", group="Volatility / Normalization", minval=1)
lookback = input.int(30, "Normalization Lookback", group="Volatility / Normalization", minval=10)
smooth   = input.int(3,  "Smoothing (EMA)",  group="Volatility / Normalization", minval=1)

// — Logic & Visuals
invertHighTrend = input.bool(true, "High Value = Large Spread (Trend)", group="Logic & Visuals")
upperThr        = input.int(70, "Upper Threshold", group="Logic & Visuals", minval=0, maxval=100)
lowerThr        = input.int(30, "Lower Threshold", group="Logic & Visuals", minval=0, maxval=100)
showBg          = input.bool(true, "Shade background for Range zone", group="Logic & Visuals")
plotStyle       = input.string("Columns", "Plot Style", options=["Columns", "Line"], group="Logic & Visuals")
plotWidth       = input.int(2, "Plot Width", minval=1, maxval=5, group="Logic & Visuals")
showMidline     = input.bool(true, "Show midline (50)", group="Logic & Visuals")

// — Signals & Alerts
onlyOnRegimeChange = input.bool(true, "Alert only on regime change", group="Signals & Alerts")
debounceBars       = input.int(2,   "Debounce bars (stability)", minval=0, maxval=50, group="Signals & Alerts")
enableRangeAlert   = input.bool(true,  "Enable Range alert", group="Signals & Alerts")
enableTrendAlert   = input.bool(true,  "Enable Trend alert", group="Signals & Alerts")

// =====================================================
// Alligator (SMMA/EMA) — no forward shift inside WASO pane (real-time safe)
// =====================================================
smmaCalc(src, length) => ta.rma(src, length)
emaCalc(src, length)  => ta.ema(src, length)

ma(src, length) =>
    useClassicAlligator or smoothType == "SMMA (RMA)" ? smmaCalc(src, length) : emaCalc(src, length)

jaw   = ma(srcOpt, jawLen)
teeth = ma(srcOpt, teethLen)
lips  = ma(srcOpt, lipsLen)

// =====================================================
// Spread vs ATR (scale-invariant)
// =====================================================
spread = (math.abs(lips - teeth) + math.abs(teeth - jaw) + math.abs(lips - jaw)) / 3.0
atr    = ta.atr(atrLen)
rel    = spread / math.max(atr, 1e-10)

// =====================================================
// Rolling 0-100 normalization (0=tight, 1=expanded)
// =====================================================
lo   = ta.lowest(rel, lookback)
hi   = ta.highest(rel, lookback)
rng  = math.max(hi - lo, 1e-10)
norm = (rel - lo) / rng

base = 100.0 * norm
osc  = invertHighTrend ? base : 100.0 * (1.0 - norm)
oscs = ta.ema(osc, smooth)

// =====================================================
// Plot & levels (oscillator panel)
// =====================================================
hU = hline(upperThr, "Upper Threshold", color=color.new(color.gray, 40))
hM = hline(50, "Midline", color=color.new(color.gray, showMidline ? 75 : 100))  // constant ref; visibility via transparency
hL = hline(lowerThr, "Lower Threshold", color=color.new(color.gray, 40))

// Colors
upColor    = color.new(color.green, 0)
downColor  = color.new(color.red,   0)
weakColor  = color.new(color.yellow,0)  // trend weakening highlight

// Base color by side of 50
col = oscs >= 50 ? upColor : downColor

// Yellow highlight when trend weakens: cross under upper threshold
fallingTrend = ta.crossunder(oscs, upperThr)
col := fallingTrend ? weakColor : col

plot(plotStyle == "Columns" ? oscs : na, "WASO",       style=plot.style_columns, linewidth=plotWidth, color=col)
plot(plotStyle == "Line"    ? oscs : na, "WASO (line)", style=plot.style_line,    linewidth=plotWidth, color=col)

// Background for likely range (compression) zone — now GRAY (neutral)
isRangeSide = invertHighTrend ? (oscs < lowerThr) : (oscs > upperThr)
bgcolor(showBg and isRangeSide ? color.new(color.gray, 85) : na)

// =====================================================
// Debounced regime detection (optional: only on regime change)
// =====================================================
condTrendRaw = invertHighTrend ? (oscs > upperThr) : (oscs < lowerThr)
condRangeRaw = invertHighTrend ? (oscs < lowerThr) : (oscs > upperThr)

var int trendCount = 0
var int rangeCount = 0
trendCount := condTrendRaw ? trendCount + 1 : 0
rangeCount := condRangeRaw ? rangeCount + 1 : 0

trendStable = trendCount > debounceBars
rangeStable = rangeCount > debounceBars

var int regime = 0  // -1=range, 0=neutral, 1=trend
prevRegime = regime
regime := trendStable ? 1 : rangeStable ? -1 : regime

// Triggers
rangeStart = rangeStable and (onlyOnRegimeChange ? prevRegime != -1 : true)
trendStart = trendStable and (onlyOnRegimeChange ? prevRegime != 1 : true)

// =====================================================
// Alerts
// =====================================================
alertcondition(enableRangeAlert and rangeStart, "Range Start", "WASO: Potential sideways/compression regime (debounced)")
alertcondition(enableTrendAlert and trendStart, "Trend Start", "WASO: Potential trend/expansion regime (debounced)")

// =====================================================
// Notes & Publication Info
// -----------------------------------------------------
// Update v1.1:
// • Range/compression background changed to neutral gray.
// • Yellow histogram highlight when oscillator drops below the upper threshold (early trend weakening).
// Defaults remain: Jaw=8, Teeth=6, Lips=2, ATR=12, Lookback=30, Smoothing=3.
//
// How to use with companions: Williams Alligator for visual expansion, MFI and Williams %R for confirmation.
// This script does NOT plot the Alligator lines; any Alligator lines shown in images are for illustration only.
//
// Original implementation inspired by Bill Williams' Alligator concept.
// No proprietary or third-party code copied. Educational use only; not financial advice.
// =====================================================
